package com.dux.commons.scripts.java.impl.javacompiler;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import javax.tools.JavaFileObject.Kind;

import com.dux.commons.scripts.java.ScriptClassLoader;



/**
 * 管理加载类
 * @author 杜祥
 * @create 2013-6-19
 */
public class ClassFileManager extends ForwardingJavaFileManager<JavaFileManager>
{

	/**
	 * 已经加载的类映射
	 */
	private final Map<String, BinaryClass> compiledClasses = new HashMap<String, BinaryClass>();
	
	/**
	 * 将用于编译的类加载
	 */
	protected ScriptClassLoaderImpl loader;
	
	/**
	 * 加载器的父类加载器
	 */
	protected ScriptClassLoader parentClassLoader;
	
	
	/**
	 * 构建一个管理加载类
	 * @param compiler
	 * 						编译器
	 * @param listener
	 * 						监听
	 */
	protected ClassFileManager(JavaCompiler compiler, DiagnosticListener<? super JavaFileObject> listener) 
	{
		super(compiler.getStandardFileManager(listener, null, null));
	}


	/**
	 * 返回java文件对象用于数据编译的存储类
	 */
	@Override
	public JavaFileObject getJavaFileForOutput(Location location,String className, Kind kind, FileObject sibling) throws IOException
	{
		BinaryClass co = new BinaryClass(className);
		
		compiledClasses.put(className, co);
		
		return co;
	}

	
	/**
	 * 返回classFileManager的classLoader实例，如果没有则创建新的classLoader
	 */
	@Override
	public synchronized ScriptClassLoaderImpl getClassLoader(Location location) 
	{
		if(loader == null)
		{
			if(parentClassLoader == null)
			{
				loader = new ScriptClassLoaderImpl(this);
			}
			else
			{
				loader = new ScriptClassLoaderImpl(this, parentClassLoader);
			}
		}
		return loader;
	}


	public void setParentClassLoader(ScriptClassLoader parentClassLoader) 
	{
		this.parentClassLoader = parentClassLoader;
	}
	
	
	/**
	 * 添加库文件,文件后缀名必须是jar。
	 * @param file
	 * @throws IOException
	 */
	public void addLibrary(File file) throws IOException
	{
		ScriptClassLoaderImpl classLoader = getClassLoader(null);
		classLoader.addLibrary(file);
	}
	
	
	/**
	 * 添加文件库列表，文件后缀名必须是jar。
	 * @param files
	 * @throws IOException
	 */
	public void addLibraries(Iterable<File> files) throws IOException
	{
		for(File f : files)
		{
			addLibrary(f);
		}
	}

	/**
	 * 获得已加载的类映射
	 * @return
	 */
	public Map<String, BinaryClass> getCompiledClasses()
	{
		return compiledClasses;
	}

	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Iterable<JavaFileObject> list(Location location, String packageName,Set<Kind> kinds, boolean recurse) throws IOException 
	{
		Iterable<JavaFileObject> objects = super.list(location, packageName, kinds, recurse);

		if(StandardLocation.CLASS_PATH.equals(location) && kinds.contains(Kind.CLASS))
		{
			List<JavaFileObject> temp = new ArrayList<JavaFileObject>();
			for(JavaFileObject object : objects)
			{
				temp.add(object);
			}

			temp.addAll(loader.getClassesForPackage(packageName));
			objects = temp;
		}

		return objects;
	}
	
	
	
	
}
